package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heima.common.dto.PageResponseResult;
import com.heima.common.dto.ResponseResult;
import com.heima.common.dto.User;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.enums.MediaEnum;
import com.heima.common.util.UserThreadLocalUtil;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.dto.WmNewsDto;
import com.heima.media.dto.WmNewsPageDto;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmNewsMaterial;
import com.heima.media.mapper.WmNewsMapper;
import com.heima.media.service.IAuditService;
import com.heima.media.service.IWmNewsMaterialService;
import com.heima.media.service.IWmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-05-16
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements IWmNewsService {


    @Autowired
    private IWmNewsMaterialService newsMaterialService;

    @Autowired
    private IAuditService auditService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Value("${topic.upDownTopic}")
    private String upDownTopic;

    /**
     * 分页获取自媒体文章列表
     *
     * @param dto 条件
     * @return
     */
    @Override
    public ResponseResult listByCondition(WmNewsPageDto dto) {
        User user = UserThreadLocalUtil.get();
        //1.构建查询条件
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        //1.1 设置状态条件
        if (dto.getStatus() != null) {
            queryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //1.2 设置频道条件  ctrl+alt+L 格式化代码
        if (dto.getChannelId() != null) {
            queryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //1.3 设置关键字模糊查询标题
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            queryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //1.4 设置时间区间
        if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            queryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }
        //1.5 设置排序
        queryWrapper.orderByDesc(WmNews::getPublishTime);
        //1.6 设置用户ID
        queryWrapper.eq(WmNews::getUserId, user.getUserId());

        //2.构建分页对象
        IPage<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //3.执行分页查询
        page = this.page(page, queryWrapper);
        //4.封装响应结果
        return new PageResponseResult(dto.getPage(), dto.getSize(), page.getTotal(), page.getRecords());
    }


    /**
     * 自媒体文章发布
     *
     * @param dto 自媒体用户提交来发布文章信息
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public ResponseResult submit(WmNewsDto dto) throws ExecutionException, InterruptedException {
        //1.验证用户是否登录
        User user = UserThreadLocalUtil.get();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.构建自媒体文章对象， 将提交来dto入参复制到自媒体文章对象中；将自媒体文章保存
        WmNews wmNews = new WmNews();
        //2.1 将dto同名同类型属性直接复制给自媒体文章对象
        BeanUtils.copyProperties(dto, wmNews);
        wmNews.setUserId(user.getUserId());
        //2.2 设置文章封面 用户指定 无图 type:0 images:[]  单图 type：1  iamges:[{素材}]  三图 type:3 iamges:[{三个素材}]  自动： type:-1  images:[]
        //2.2.2 处理单图以及多图封面类型
        List<ImageDto> coverImages = dto.getImages();

        //2.2.2.0 获取正文中图片
        List<ImageDto> conententImages = getImagesFromContent(dto.getContent());

        if (!CollectionUtils.isEmpty(coverImages)) {
            //将封面图片集合中图片地址采用逗号拼接
            String images = coverImages.stream().map(ImageDto::getUrl).collect(Collectors.joining(","));
            wmNews.setImages(images);
        } else {
            //2.2.3 处理封面为自动类型 如果内容中没有图片 则类型设置为无图；内容图片数量小于3则设置为单图 截图第一张图片；图片数量大于3则多图 截取前三张图片
            if (CollectionUtils.isEmpty(conententImages)) {
                //无图类型
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_NONE.getVal());
            } else if (conententImages.size() < 3) {
                //单图
                String url = conententImages.get(0).getUrl();
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_ONE.getVal());
                wmNews.setImages(url);
            } else {
                //三图
                List<ImageDto> imageDtoList = conententImages.subList(0, 3);
                String images = imageDtoList.stream().map(ImageDto::getUrl).collect(Collectors.joining(","));
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_MANY.getVal());
                wmNews.setImages(images);
            }
        }
        //2.3 执行保存自媒体文章
        this.save(wmNews);

        //3.非草稿状态需要记录文章跟素材引用关系 存入文章素材关系表中
        saveArticleMaterialRelation(coverImages, MediaEnum.MATERIAL_TYPE_REF_TYPE_CONVERIMG.getVal(), wmNews.getId());
        saveArticleMaterialRelation(conententImages, MediaEnum.MATERIAL_TYPE_REF_TYPE_CONTENTIMG.getVal(), wmNews.getId());


        //TODO 完成对用户发布文章进行审核（异步审核）
        String xid = RootContext.getXID();
        auditService.audit(wmNews);
        return ResponseResult.okResult();
    }


    /**
     * 将文章跟素材建立关联
     *
     * @param imageDtoList 内容图片集合 或者 正文图片集合
     * @param type         0：内容引入  1：封面引用
     * @param newsId       文章ID
     */
    private void saveArticleMaterialRelation(List<ImageDto> imageDtoList, Integer type, Integer newsId) {
        int ord = 0;
        if (!CollectionUtils.isEmpty(imageDtoList)) {
            for (ImageDto imageDto : imageDtoList) {
                WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
                wmNewsMaterial.setMaterialId(imageDto.getId());
                wmNewsMaterial.setNewsId(newsId);
                wmNewsMaterial.setType(type);
                wmNewsMaterial.setOrd(ord++);
                newsMaterialService.save(wmNewsMaterial);
            }
        }
    }


    /**
     * 从文章正文中获取图片
     *
     * @param content 文章正文
     *                content: "[{\"type\":\"text\",\"value\":\"第一段内容\\n\"},{\"type\":\"image\",\"value\":\"http://192.168.137.136:9000/leadnews/0edb5264-a033-4a47-a586-43a51b4ce73a.png\",\"id\":120}]
     * @return
     */
    private List<ImageDto> getImagesFromContent(String content) {
        //1.采用FastJSON转换  将字符串转为java对象 String---->ContentDTO
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        //2.遍历段落集合 获取图片
        if (!CollectionUtils.isEmpty(contentDtos)) {
            List<ImageDto> imageDtos = new ArrayList<>();
            for (ContentDto contentDto : contentDtos) {
                if ("image".equals(contentDto.getType())) {
                    ImageDto imageDto = new ImageDto();
                    imageDto.setId(contentDto.getId());
                    imageDto.setUrl(contentDto.getValue());
                    imageDtos.add(imageDto);
                }
            }
            return imageDtos;
        }
        return null;
    }


    /**
     * 文章上下架
     * 1.更新自媒体文章状态   2.发送下架发布文章消息
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.根据自媒体文章ID查询文章对象
        WmNews wmNews = this.getById(dto.getId());
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2.判断文章审核状态 只有被审核通过的文章才能被下架
        if (!wmNews.getStatus().equals(MediaEnum.NEWS_SUBMIT_STATUS_PUBLISH.getVal())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_CAN_NOT_UPDATE);
        }
        //3.修改自媒体文章状态
        wmNews.setEnable(dto.getEnable() == 0 ? false : true);
        this.updateById(wmNews);

        //4.发送消息到Kafka
        //4.1 构建发送消息HashMap
        HashMap<String, Object> map = new HashMap<>();
        map.put("articleId", wmNews.getArticleId());
        map.put("isDown", dto.getEnable() == 1 ? false : true);
        //4.2 将参数转为JSON字符串
        String dataStr = JSON.toJSONString(map);
        kafkaTemplate.send(upDownTopic, dataStr);
        return ResponseResult.okResult();
    }

}
